package cn.itsource.basic.service.impl;

import cn.itsource.basic.constant.WechatConstant;
import cn.itsource.basic.domain.dto.BinderDto;
import cn.itsource.basic.domain.dto.LoginDto;
import cn.itsource.basic.exception.CustomException;
import cn.itsource.basic.jwt.JwtUtils;
import cn.itsource.basic.jwt.RsaUtils;
import cn.itsource.basic.jwt.UserInfo;
import cn.itsource.basic.service.ILoginService;
import cn.itsource.basic.util.AjaxResult;
import cn.itsource.basic.util.HttpClientUtils;
import cn.itsource.basic.util.MD5Utils;
import cn.itsource.basic.util.StrUtils;
import cn.itsource.system.domain.Menu;
import cn.itsource.system.domain.Permission;
import cn.itsource.system.mapper.MenuMapper;
import cn.itsource.system.mapper.PermissionMapper;
import cn.itsource.user.domain.Logininfo;
import cn.itsource.user.domain.User;
import cn.itsource.user.domain.Wxuser;
import cn.itsource.user.mapper.LogininfoMapper;
import cn.itsource.user.mapper.UserMapper;
import cn.itsource.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.PrivateKey;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private PermissionMapper permissionMapper;


    /**
     * 账号密码登录
     * @param dto
     * @return
     */
    @Override
    public Object accountLogin(LoginDto dto) throws Exception {
        //非空校验
        if(StringUtils.isEmpty(dto.getUsername()) || StringUtils.isEmpty(dto.getPassword())){
            throw new CustomException("账号或密码不能为空！");
        }
        //判断该用户是否存在
        Logininfo logininfo = logininfoMapper.queryByUsernameAndType(dto.getUsername(),dto.getType());
        if(logininfo == null){
            throw new CustomException("该用户不存在");
        }
        //判断密码是否正确
        String importPassword = MD5Utils.encrypByMd5(logininfo.getSalt()+dto.getPassword());

        if(!logininfo.getPassword().equals(importPassword)){
            throw new CustomException("用户名或者密码错误！");
        }
//        //免密登录
//            // 生成UUID作为key 将 logininfo作为value保存到Redis中 过期时间30 分钟
//        String token = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
//        Map<String, Object> map = new HashMap<>();
//        map.put("token",token);
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        map.put("logininfo",logininfo);

        return loginSuccessHanlder(logininfo);
    }

    private Map<String,Object> loginSuccessHanlder(Logininfo logininfo) throws Exception {
        UserInfo userInfo = new UserInfo();
        //存放登录信息
        userInfo.setLogininfo(logininfo);
        //判断是主站用户还是管理员
        if(logininfo.getType() == 1){
            //是主站用户就将menus和permissions设置为null
            userInfo.setMenus(null);
            userInfo.setPermissions(null);
        }else {
            //管理员用户 需要将menus和permissions查询出来进行加密处理
            List<Menu> menus = menuMapper.queryOwnMenusByLoginInfoId(logininfo.getId());//获取用户对应的menus
            List<String> permissions = permissionMapper.ownSn(logininfo.getId());//获取用户对应的permissions
            //是管理员用户 需要将menus和permissions添加进去
            userInfo.setMenus(menus);
            userInfo.setPermissions(permissions);
        }
        //加密 用私钥加密jwttoken
        PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("hrm_auth_rsa").getFile());
        String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, 1440);
        Map<String ,Object> map = new HashMap<>();
        map.put("token",token);
        map.put("logininfo",logininfo);
        map.put("menus",userInfo.getMenus());
        map.put("permissions",userInfo.getPermissions());
        System.out.println(userInfo.getPermissions());
        return map;

    }


    /**
     * 第三方微信登录
     * @param map
     * @return
     */
    @Override
    public AjaxResult wechartLogin(Map<String,String> map) throws Exception {
        //非空校验
        String code = map.get("code");
        if(code == null){
            throw new CustomException("参数异常！");
        }
        //拿到获取token的接口
        String getTokenUrl = WechatConstant.GET_TOKEN_URL
                .replace("APPID", WechatConstant.APPID)
                .replace("SECRET", WechatConstant.SECRET)
                .replace("CODE",code);
        //请求wx服务器 得到wx的用户信息 返回的result是json字符串 需要将其转为json对象
        String result = HttpClientUtils.httpGet(getTokenUrl);
        //将resultJSON的格式转为json对象
        JSONObject jo = JSONObject.parseObject(result);

        //获取openID
        String openid = jo.getString("openid");
        //获取token
        String token = jo.getString("access_token");

        //根据json对象的openID 查询t_wxuser用户表
        Wxuser wxuser = wxuserMapper.queryByOpenid(jo.getString("openid"));
        //判断wxuser是否已经存在，存在就查询logininfo，不存在就返回token和openID
        if(wxuser != null){
            //根据wxuser里面的userid 查询logininfo信息  传入t_user表的id找到里面的loginfo_id 去连表t_logininfo表的id 查找logininfo信息
            Logininfo logininfo = logininfoMapper.queryByUserId(wxuser.getUserId());
            //判断logininfo信息是否存在
            if(logininfo == null){
                throw new CustomException("参数异常！");
            }
//            //logininfo信息存在就免密登录
//                //生成UUID作为key 将 logininfo作为value保存到Redis中 过期时间30 分钟
//            String tokenLogin = UUID.randomUUID().toString();
//            redisTemplate.opsForValue().set(tokenLogin,logininfo,30, TimeUnit.MINUTES);
//            Map<String, Object> map2 = new HashMap<>();
//            map2.put("token",tokenLogin);
//            logininfo.setSalt(null);
//            logininfo.setPassword(null);
//            map2.put("logininfo",logininfo);
            return AjaxResult.me().setResultObj(loginSuccessHanlder(logininfo));
        }
        //不存在就返回token和openID
        String binderUrl = "?token="+token+"&openid="+openid;
        return AjaxResult.me().setSuccess(false).setResultObj(binderUrl);
    }

    /**
     * 微信绑定
     * @param dto
     * @return
     */
    @Override
    public AjaxResult binder(BinderDto dto) throws Exception {
        //空参数校验
        if(StringUtils.isEmpty(dto.getAccessToken()) ||
           StringUtils.isEmpty(dto.getOpenId()) ||
           StringUtils.isEmpty(dto.getPhone()) ||
           StringUtils.isEmpty(dto.getPassword())
        ){
            throw new CustomException("参数异常");
        }
        //拼接发送获取微信信息的url
        String url = WechatConstant.GET_INFO_URL
                .replace("ACCESS_TOKEN", dto.getAccessToken())
                .replace("OPENID", dto.getOpenId());
        //发送请求获取微信信息
        String result = HttpClientUtils.httpGet(url);
        //result是json字符串 将其转为json对象
        JSONObject jo = JSONObject.parseObject(result);
        //初始化参数
        Wxuser wxuser = initWxuser(jo);
        //查询longininfo 判断dto.getphone该账户是否已经通过网页注册
        Logininfo logininfo = logininfoMapper.queryByUsernameAndType(dto.getPhone(), 1);

        if(logininfo != null){
            //若果不为空，就需要绑定t_wxuser的userid为 t_user表单的id
            User user = userMapper.queryByUserName(dto.getPhone());
            //绑定t_wxuser的userid为 t_user表单的自增id
            wxuser.setUserId(user.getId());
            wxuserMapper.add(wxuser);
//            //最后免密码登录
//                //生成UUID作为key 将 logininfo作为value保存到Redis中 过期时间30 分钟
//            String tokenLogin = UUID.randomUUID().toString();
//            redisTemplate.opsForValue().set(tokenLogin,logininfo,30, TimeUnit.MINUTES);
//            Map<String, Object> map2 = new HashMap<>();
//            map2.put("token",tokenLogin);
//            logininfo.setSalt(null);
//            logininfo.setPassword(null);
//            map2.put("logininfo",logininfo);
//            return AjaxResult.me().setResultObj(map2);
        }else {
            //如果是第一次，既没有网页注册过也没有微信绑定过 就需要注册用户保存 添加三张表的信息
            //         生成盐值随机字符串（32位）保留
            String saltValue = StrUtils.getComplexRandomString(32);
            //         使用MD5工具类加密密码（密码需要拼接盐值一起加密）
            String md5Password = MD5Utils.encrypByMd5(saltValue + dto.getPassword());

            //        构建user和login_info对象，初始化参数
            User user = initUser(dto.getPhone(),saltValue,md5Password);
            //将原来查询出来的空的logininfo 添加对象
            logininfo = user2Longininfo(user);
            //         ①先保存login_info，获取自增id
            logininfoMapper.add(logininfo);
            //         ②再保存user
            user.setLogininfoId(logininfo.getId());
            userMapper.add(user);

            //③最后添加保存t_wxuser的userid为 t_user表单的id
            wxuser.setUserId(user.getId());
            wxuserMapper.add(wxuser);
        }
//        //最后免密码登录
//            //生成UUID作为key 将 logininfo作为value保存到Redis中 过期时间30 分钟
//        String tokenLogin = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(tokenLogin,logininfo,30, TimeUnit.MINUTES);
//        Map<String, Object> map2 = new HashMap<>();
//        map2.put("token",tokenLogin);
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        map2.put("logininfo",logininfo);
        return AjaxResult.me().setResultObj(loginSuccessHanlder(logininfo));
    }

    private Wxuser initWxuser(JSONObject jo) {
        Wxuser wxuser = new Wxuser();
        wxuser.setSex(jo.getInteger("sex"));
        wxuser.setOpenid(jo.getString("openid"));
        wxuser.setNickname(jo.getString("nickname"));
        wxuser.setAddress(jo.getString("country"));
        wxuser.setHeadimgurl(jo.getString("headimgurl"));
        wxuser.setUnionid(jo.getString("unionid"));
        return wxuser;
    }

    private Logininfo user2Longininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);//copyProperties(要拷贝的源对象，拷贝到的目标对象)
        logininfo.setDisable(1);
        logininfo.setType(1);
        return logininfo;
    }

    private User initUser(String mobile, String salt, String md5Password) {
        User user = new User();
        user.setPhone(mobile);
        user.setSalt(salt);
        user.setPassword(md5Password);
        user.setState(1);
        user.setCreatetime(new Date());
        user.setUsername(mobile);
        return user;
    }

}
